module Explode.Characters;
import Graphics.IGraphics;
import System.Serializer;
import Explode.Stage;
import System.Console;

public interface ICharacter : IDrawingEntry {
//public interface ICharacter : IDrawingEntry , ISerializer {
	void  x(float x);
	void  y(float y);
	void  z(float z);
	float x();
	float y();
	float z();

	int hFace(); //	顔の向き(横)
	int vFace(); // 顔の向き(縦)

	bool alive();
	int attribute();
	bool action();
	bool drawingEntry( IGraphics g);
	bool draw( IGraphics g );
	bool kill();
	void reset();
	int bx();
	int by();
	int xMove();
	int yMove();
	int life();
	int score();
	void moveTo( int x , int y);
	void moveBy( int x , int y);
	bool collision( ICharacter obj );
	bool onCollided( ICharacter obj );
	bool onKicked( ICharacter obj , int pow );
} //

public abstract class BaseCharacter : ICharacter {
	protected int _x , _y , _z , _life , _attribute , _xMove , _yMove;
	protected bool _alive;
	protected int  _score;

	protected static const int WALKSPEED = 2;
	protected int _hFace = 1 ,_vFace = 1 , _animCnt = 0 ;
	protected int _goldCnt = 0;

	protected ISprite _sprite;
	protected ITexture _texture;
	public ITexture texture(){return _texture;}

	public float x(){return _x;}
	public float y(){return _y;}
	public float z(){return _z;}
	public void x( float v ){ _x = cast(int)v;}
	public void y( float v ){ _y = cast(int)v;}
	public void z( float v ){ _z = cast(int)v;}

	public int hFace(){ return _hFace;}
	public int vFace(){ return _vFace;}

	public void reset(){};
	
	/**
	*	どのマス目に位置するかを得る
	*/
	public int bx(){return ( _x + Blocks.HALFWIDTH  ) >> Blocks.SHIFTX;}
	public int by(){return ( _y + Blocks.HALFHEIGHT ) >> Blocks.SHIFTY;}
		
	public int  life() {return _life;}
	public bool alive(){return _alive;}
	public int  score(){return _score;}

	public int xMove(){return _xMove;}
	public int yMove(){return _yMove;}

	public int attribute() {return _attribute;};

	public void moveBy( int x , int y){
		moveTo( _x + x , _y + y );
	} //

	public bool collision( ICharacter obj ) {
		return ( bx == obj.bx && by == obj.by );
	} //
	public bool onCollided( ICharacter obj ){return false;};
	
	//abstract
	public abstract bool action();
	public abstract void moveTo( int x , int y );
	public abstract bool kill();
	public abstract bool drawingEntry( IGraphics g );
	public abstract bool draw( IGraphics g );

	public void deserialize( SerialData s){}
	public SerialData serialize(){return null;}
	public static ISerializer create( SerialData s ){
		return null;
	}

	public bool onKicked( ICharacter obj , int pow ) {
		return false;
	} //

} //


public class CharacterGroup : IDrawingEntry , ISerializer {
	protected float _z;
	public float x(){return 0;}
	public float y(){return 0;}
	public float z(){return _z;}
	
	protected bool _groupDrawing = false;
	
	/*
	*	グループメンバのZ座標が全て同じ場合(シューティングの弾など)に、
	*	groupDrawingを有効にすると、CharacterGroupがまとめてdrawingEntryする。
	*	それによってZソートのコストを抑える事が出来る。
	*/
	public bool groupDrawing() { return _groupDrawing;}
	public void groupDrawing( bool v ) { _groupDrawing = v;}
	
	private ICharacter[] _vc;
	private int _ptr;

	ICharacter opIndex( int x ) {
		return _vc[ x ] ;
	} //
	bool opIn( ICharacter cc ) {
		for ( int i = _vc.length - 1 ; i >= 0 ; i-- ) {
			if ( _vc[ i ] is cc ) return true;
		}
		return false;
	} //
	public int length(){
		return _ptr;
	} //

	public this( int max = 1024 ){
		_vc = new ICharacter[ max ];
		_z = 0;
	} //
	
	public ICharacter getMember( int num ) {
		if(num >= _vc.length)return null;
		return _vc[num];
	} //

	public ICharacter idle(){
		for( int i = 0 ; i < _ptr ; i++) {
			if( !_vc[i].alive ) return _vc[i];
		}
		return null;
	} //

	public bool add( ICharacter cc ) {
		if ( _ptr >= _vc.length )return false;
		_vc[ _ptr ] = cc;
		_ptr++;
		return true;
	} //

	public int add ( ICharacter[] cc ) {
		int cnt = 0;
		for ( int i = cc.length - 1 ; i >= 0 ; i-- ) {
			if( add( cc[i] ) ) cnt++;
		}
		return cnt;
	} //
	public bool remove( ICharacter cc ) {
		for ( int i = _vc.length - 1 ; i >= 0 ; i-- ) {
			if ( _vc[ i ] is cc ) {
				_vc[ i ] = _vc[ _ptr - 1 ];
				_vc[ _ptr - 1 ]=null;
				_ptr--;
				return true;
			}
		}
		return false;
	} //
	public int remove( ICharacter[] cc ) {
		int cnt = 0;
		for ( int i = cc.length - 1 ; i >= 0 ; i-- ) {
			if( remove( cc[i] ) ) cnt++;
		}
		return cnt;
	} //

	public bool clear() {
		for( int i = _ptr -1 ; i >= 0 ; i-- ) {
			_vc[i].kill();
			_vc[i] = null;
		}
		_ptr = 0;
		return true;
	} //

	public bool drawingEntry( IGraphics g ) {
		if ( _groupDrawing ) {
			for ( int i = _ptr - 1 ; i >= 0 ; i-- ) {
				ICharacter cc = _vc[i];
				if ( cc.alive ) {
					cc.drawingEntry( g );
					_z = _vc[0].z;
					g.addDrawingEntry( this );
				}
			}
		} else {
			for ( int i = _ptr - 1 ; i >= 0 ; i-- ) {
				ICharacter cc = _vc[i];
				if ( cc.alive ) {
					cc.drawingEntry( g );
				}
			}
		}
		return true;
	} //

	public bool draw( IGraphics g ) {
		if ( _groupDrawing ) {
			for ( int i = _ptr - 1 ; i >= 0 ; i-- ) {
				ICharacter cc = _vc[i];
				if ( cc.alive ) {
					cc.draw( g );
				}
			}
		}
		return true;
	} //

	public bool action() {
		for ( int i = _ptr - 1 ; i >= 0 ; i--) {
			ICharacter cc = _vc[i];
//			if( cc.alive )Console.writeln("cc!");
			if ( cc.alive )
				cc.action();
//			else
//				remove(cc);
		}
		return true;
	} //

	public void reset() {
		for ( int i  = _ptr - 1 ; i >= 0 ; i-- ) _vc[i].reset();
	} //

	public void kill() {
		for ( int i = _ptr - 1 ; i >= 0 ; i-- )_vc[i].kill();
	} //

	public bool collision( ICharacter m ) {
		bool ret = false;
		for( int i = _ptr -1 ; i >= 0 ; i-- ){
			ICharacter cc = _vc[i];
			if ( cc is m || !cc.alive )	continue;
			 if ( cc.collision( m ) ) {
				if ( cc.onCollided( m ) ) {
					m.onCollided(cc);
				}
				ret = true;
			 }
		}
		return ret;
	} //

	public void collision( CharacterGroup g ) {
		for ( int i = g._ptr - 1 ; i >= 0 ; i-- ) {
			collision( g._vc[i] );
		}
	} //

	public void deserialize( SerialData s ){
		reset();
		while( s.hasNext ) {
//			add( );
		}
	} //
	public SerialData serialize(){
		return null;
	} //
	public static ISerializer create( SerialData s ){
//		CharacterGroup ret = new CharacterGroup( );
//		ret.deserialize( s );
		return null;
	}

	public bool onKicked( ICharacter obj , int pow ) {
		return false;
	} //

} //